﻿#ifdef WIN32

#include "Network/TCPServer.h"
#include "Network/TCPClient.h"
#include "Async/PackagedTask.h"

#include "Platform/Socket/WindowsSocketCommon.h"
#include "SocketPlatform.h"
#define UNICODE
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>

bool CTCPServer::IsPortOccupied(const SIPAddress& IP,uint16_t Port)
{
    //初始化WSA
    CWindowsSocketContext::Get();

    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s == INVALID_SOCKET)
    {
        return true;
    }

    sockaddr_in Service;
    Service.sin_family = AF_INET;
    Service.sin_port = htons(Port);
    if (IP.IsIPv6())
    {
        memcpy(&Service.sin_addr, IP.IP.IPv6, sizeof(IP.IP.IPv6));
    }
    else
    {
        memcpy(&Service.sin_addr, IP.IP.IPv4, sizeof(IP.IP.IPv4));
    }

    if (bind(s, (SOCKADDR *)&Service, sizeof(Service)) == SOCKET_ERROR)
    {
        closesocket(s);
        return true;
    }

    closesocket(s);
    return false;
}

void CTCPServer::Listen(const SIPAddress& IP, uint16_t Port)
{
    //初始化WSA
    CWindowsSocketContext::Get();


    std::lock_guard<std::mutex> Lock(ListenSocketMutex);
    if(State!=ETCPServerState::Idle)
    {
        //当前TCP服务器状态不是空闲状态,不能再次监听
        OnErrorOccured.ExecuteIfBound(ETCPServerError::CreateSocketWhenListeningError);
        return;
    }

    //创建socket
    PlatformData->Socket =socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (PlatformData->Socket == INVALID_SOCKET)
    {
        //创建socket失败
        OnErrorOccured.ExecuteIfBound(ETCPServerError::CreateSocketError);
        return;
    }

    //绑定socket
    sockaddr_in Service;
    Service.sin_family = AF_INET;
    Service.sin_port = htons(Port);
    if (IP.IsIPv6())
    {
        memcpy(&Service.sin_addr, IP.IP.IPv6, sizeof(IP.IP.IPv6));
    }
    else
    {
        memcpy(&Service.sin_addr, IP.IP.IPv4, sizeof(IP.IP.IPv4));
    }

    if (bind(PlatformData->Socket, (SOCKADDR *)&Service, sizeof(Service)) == SOCKET_ERROR)
    {
        closesocket(PlatformData->Socket);
        //绑定socket失败
        OnErrorOccured.ExecuteIfBound(ETCPServerError::BindAddressAndPortError);
        return;
    }

    //开始监听
    if (listen(PlatformData->Socket, SOMAXCONN) == SOCKET_ERROR)
    {
        closesocket(PlatformData->Socket);
        //listen失败
        OnErrorOccured.ExecuteIfBound(ETCPServerError::ListenError);
        return;
    }

    //设置为非阻塞
    u_long iMode = 1;
    ioctlsocket(PlatformData->Socket, FIONBIO, &iMode);

    State=ETCPServerState::Listening;

    StartAcceptTask();
}


void CTCPServer::StartAcceptTask()
{
    TThreadSafeWeakPtr<CTCPServer> This=AsShared();

    std::shared_ptr<CPackagedTask<void>> 
        AcceptTask = WH::CreateAsyncTask<void>(
        [This](bool& )mutable ->void
    {
        auto _This=This.Lock();
        if(!_This)
        {
            return;
        }

        SOCKET ClientSocket;
        {
            std::lock_guard<std::mutex> Lock(_This->ListenSocketMutex);
            if(_This->PlatformData->Socket==INVALID_SOCKET)
            {
                //socket已经关闭
                return;
            }

            sockaddr_in addr;
            int32_t addrLen = sizeof(addr);
            ClientSocket = accept(_This->PlatformData->Socket, (sockaddr *)&addr, &addrLen);

        }

        if (ClientSocket == INVALID_SOCKET)
        {
            //没有客户端连接
            _This->StartAcceptTask();
            return;
        }

        {
            std::lock_guard<std::mutex> Lock(_This->PendingAcceptSocketsMutex);
            CSocketPlatformData* ClientSocketData = new CSocketPlatformData();
            ClientSocketData->Socket = ClientSocket; 
            _This->PendingAcceptSockets.push(ClientSocketData);
        }

        //继续接受下一个客户端
        _This->StartAcceptTask();

        //通知客户端连接成功,
        //之所以放在StartAcceptTask()之后是因为这个操作可能会比较耗时
        //可能影响下一次accept
        _This->OnClientConnected.ExecuteIfBound();

    });        

    AcceptTask->Start();
    
}


void CTCPServer::StopListen()
{
    if(State!=ETCPServerState::Listening)
    {
        return;
    }

    //关闭socket
    {
        std::lock_guard<std::mutex> Lock(ListenSocketMutex);
        closesocket(PlatformData->Socket);
        PlatformData->Socket=INVALID_SOCKET;
        State=ETCPServerState::Idle;
    }

    //清空待处理的socket
    {
        std::lock_guard<std::mutex> Lock(PendingAcceptSocketsMutex);
        while(!PendingAcceptSockets.empty())
        {
            auto Socket=PendingAcceptSockets.front();
            PendingAcceptSockets.pop();

            closesocket(Socket->Socket);
            delete Socket;
        }
    }

}


#endif